package com.lzh.persevere.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.lzh.persevere.mapper.*;
import com.lzh.persevere.model.entity.*;
import com.lzh.persevere.model.qo.qo.ArticlePageQO;
import com.lzh.persevere.model.ro.article.AddArticleRO;
import com.lzh.persevere.model.vo.article.ArticleDetailVO;
import com.lzh.persevere.model.vo.article.ArticleInfoVO;
import com.lzh.persevere.model.vo.article.CategoryArticleVO;
import com.lzh.persevere.model.vo.tag.ArticleTagInfoVO;
import com.lzh.persevere.service.ArticleInfoService;
import com.lzh.persevere.template.PageAbstractTemplate;
import com.lzh.persevere.utils.HtmlHeadingIdProcessor;
import com.lzh.persevere.utils.MarkdownUtils;
import com.lzh.persevere.utils.SecurityUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文章表服务实现类
 *
 * @author luzhiheng
 * @since 2025-07-15
 */
@Service
public class ArticleInfoServiceImpl extends ServiceImpl<ArticleInfoMapper, ArticleInfo> implements ArticleInfoService {

    @Resource
    private RedisCacheService redisCacheService;

    @Resource
    private TagInfoMapper tagInfoMapper;

    @Resource
    private UserMapper userMapper;

    @Resource
    private CategoryInfoMapper categoryInfoMapper;

    @Resource
    private CommentMapper commentMapper;

    @Resource
    private ArticleTagMapper articleTagMapper;

    @Resource
    private FileInfoMapper fileInfoMapper;

    @Resource
    private LikeArticleInfoMapper likeArticleInfoMapper;

    @Resource
    private CollectArticleInfoMapper collectArticleInfoMapper;

    @Override
    public Map<String, Object> pageList(ArticlePageQO qo) {
        Map<String, Object> otherQueryMap = new HashMap<>();
        otherQueryMap.put("tagId", qo.getTagId());
        PageAbstractTemplate template = new PageAbstractTemplate() {
            @Override
            public Integer countTotal() {
                return baseMapper.countList(getQueryMap(qo.getPageModel(), otherQueryMap));
            }

            @Override
            public List<Map<String, Object>> queryPageList() {
                List<Map<String, Object>> pageList = baseMapper.getPageList(queryMap);
                Map<String, String> allUserIdNickNameMap = redisCacheService.getAllUserIdNickNameMap();
                if (CollectionUtil.isNotEmpty(pageList)) {
                    List<Long> articleIdList = pageList.stream().map(e -> Long.valueOf(e.get("id").toString())).collect(Collectors.toList());
                    pageList.forEach(map -> {
                        map.put("createNickName", allUserIdNickNameMap.get(String.valueOf(map.get("createUserId"))));
                        map.put("updateNickName", allUserIdNickNameMap.get(String.valueOf(map.get("updateUserId"))));
                    });

                    // 获取文章标签
                    List<ArticleTagInfoVO> tagInfoList = CollectionUtil.isNotEmpty(articleIdList) ? tagInfoMapper.selectByArticleIdList(articleIdList) : new ArrayList<>();
                    Map<Long, List<ArticleTagInfoVO>> articleIdTagMap = tagInfoList.stream().collect(Collectors.groupingBy(ArticleTagInfoVO::getArticleId));
                    pageList.forEach(e -> {
                        List<ArticleTagInfoVO> tagList = articleIdTagMap.get(Long.valueOf(e.get("id").toString()));
                        if (CollectionUtil.isNotEmpty(tagList)) {
                            e.put("articleTagList", tagList);
                        }
                    });
                }
                return pageList;
            }
        };
        return template.queryPage();
    }

    @Override
    public ArticleDetailVO findArticleDetail(Long id) {
        ArticleInfo articleInfo = baseMapper.selectById(id);
        if (articleInfo == null) {
            return null;
        }
        // 文章详情
        ArticleDetailVO vo = new ArticleDetailVO();
        vo.setArticleInfo(articleInfo);
        // 标签
        List<TagInfo> tagInfoList = tagInfoMapper.selectByArticleId(id);
        vo.setTagList(tagInfoList);
        // 用户信息
        User user = userMapper.selectById(articleInfo.getCreateUserId());
        user.setPassword(null);
        user.setAddress(null);
        user.setEmail(null);
        user.setPhone(null);
        vo.setUserInfo(user);
        vo.setIsLike(likeArticleInfoMapper.selectByArticleIdAndUserId(id, SecurityUtils.getUserId()) != null);
        vo.setIsCollect(collectArticleInfoMapper.selectByArticleIdAndUserId(id, SecurityUtils.getUserId()) != null);
        return vo;
    }

    @Override
    public List<CategoryArticleVO> findAllCategoryArticleList() {
        List<CategoryInfo> categoryInfoList = categoryInfoMapper.selectList(null);
        // 获取每个分类下的文章数量
        int topN = 6;
        // 文章ID列表
        List<Long> articleIdList = new ArrayList<>();
        List<CategoryArticleVO> categoryArticleVOList = categoryInfoList.stream().map(e -> {
            CategoryArticleVO vo = new CategoryArticleVO();
            vo.setCategoryId(e.getId());
            vo.setCategoryName(e.getCategoryName());
            // 获取文章列表
            List<ArticleInfoVO> articleInfoVOList = BeanUtil.copyToList(baseMapper.selectByCategoryId(e.getId(), topN), ArticleInfoVO.class);
            vo.setArticleInfoList(articleInfoVOList);
            articleInfoVOList.forEach(v -> {
                articleIdList.add(v.getId());
            });
            return vo;
        }).collect(Collectors.toList());
        // 获取文章标签
        List<ArticleTagInfoVO> tagInfoList = CollectionUtil.isNotEmpty(articleIdList) ? tagInfoMapper.selectByArticleIdList(articleIdList) : new ArrayList<>();
        Map<Long, List<ArticleTagInfoVO>> articleIdTagMap = tagInfoList.stream().collect(Collectors.groupingBy(ArticleTagInfoVO::getArticleId));
        categoryArticleVOList.forEach(e -> {
            if (CollectionUtil.isNotEmpty(e.getArticleInfoList())) {
                e.getArticleInfoList().forEach(v -> {
                    v.setArticleTagList(articleIdTagMap.get(v.getId()));
                });
            }
        });

        categoryArticleVOList = categoryArticleVOList.stream().filter(e -> CollectionUtil.isNotEmpty(e.getArticleInfoList())).collect(Collectors.toList());
        return categoryArticleVOList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean addArticle(AddArticleRO ro) {
        ArticleInfo articleInfo = BeanUtil.copyProperties(ro, ArticleInfo.class);
        articleInfo.setHtmlContent(HtmlHeadingIdProcessor.addUniqueIdsToHeadings(MarkdownUtils.markdownToHtml(ro.getMdContent())));
        articleInfo.setWordCount(ro.getMdContent().length());
        baseMapper.insert(articleInfo);

        List<ArticleTag> articleTagList = ro.getTagIds().stream()
                .map(e -> {
                            ArticleTag articleTag = new ArticleTag().setArticleId(articleInfo.getId()).setTagId(e);
                            articleTag.setCreateUserId(Objects.requireNonNull(SecurityUtils.getUserId()).toString());
                            return articleTag;
                        }
                )
                .collect(Collectors.toList());
        articleTagMapper.insertBatch(articleTagList);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean editArticle(AddArticleRO ro) {
        ArticleInfo articleInfo = BeanUtil.copyProperties(ro, ArticleInfo.class);
        articleInfo.setHtmlContent(HtmlHeadingIdProcessor.addUniqueIdsToHeadings(MarkdownUtils.markdownToHtml(ro.getMdContent())));
        articleInfo.setWordCount(ro.getMdContent().length());
        baseMapper.updateById(articleInfo);

        articleTagMapper.deleteByArticleId(articleInfo.getId());
        List<ArticleTag> articleTagList = ro.getTagIds().stream()
                .map(e -> {
                            ArticleTag articleTag = new ArticleTag().setArticleId(articleInfo.getId()).setTagId(e);
                            articleTag.setCreateUserId(Objects.requireNonNull(SecurityUtils.getUserId()).toString());
                            return articleTag;
                        }
                )
                .collect(Collectors.toList());
        articleTagMapper.insertBatch(articleTagList);
        return true;
    }

    @Override
    public List<ArticleInfo> findRecommendArticle() {
        List<ArticleInfo> articleInfoList = baseMapper.selectRecommendArticleTopN(3);
        return articleInfoList;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean likeArticle(Long articleId) {
        ArticleInfo articleInfo = baseMapper.selectById(articleId);
        LikeArticleInfo likeArticleInfo = likeArticleInfoMapper.selectByArticleIdAndUserId(articleId, SecurityUtils.getUserId());
        if (likeArticleInfo == null) {
            // 该用户未点赞
            likeArticleInfoMapper.insert(new LikeArticleInfo().setArticleId(articleId));
            articleInfo.setLikeCount(articleInfo.getLikeCount() + 1);
        } else {
            // 该用户已点赞
            likeArticleInfoMapper.deleteById(likeArticleInfo);
            articleInfo.setLikeCount(articleInfo.getLikeCount() - 1);
        }
        baseMapper.updateById(articleInfo);
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean collectArticle(Long articleId) {
        ArticleInfo articleInfo = baseMapper.selectById(articleId);
        CollectArticleInfo collectArticleInfo = collectArticleInfoMapper.selectByArticleIdAndUserId(articleId, SecurityUtils.getUserId());
        if (collectArticleInfo == null) {
            // 该用户未收藏
            collectArticleInfoMapper.insert(new CollectArticleInfo().setArticleId(articleId));
            articleInfo.setCollectCount(articleInfo.getCollectCount() + 1);
        } else {
            // 该用户已收藏
            collectArticleInfoMapper.deleteById(collectArticleInfo);
            articleInfo.setCollectCount(articleInfo.getCollectCount() - 1);
        }
        baseMapper.updateById(articleInfo);
        return true;
    }

    @Override
    public List<ArticleTagInfoVO> findTagListByCategory(Long categoryId) {
        return baseMapper.selectTagListByCategoryId(categoryId);
    }
}
